//
// Created by twetec on 25-9-20.
//

#include <gtest/gtest.h>

#include <memory>
// #include <asio2/asio2.hpp>
#include <boost/asio.hpp>
#include <random>
// #include <boost/asio/co_spawn.hpp>
// #include <boost/asio/signal_set.hpp>

#include <chrono>
using namespace std::chrono_literals;


namespace tests::probe
{
void myTask()
{
    std::cout << "myTask: " << std::this_thread::get_id << std::endl;
    std::this_thread::sleep_for(3s);
}

TEST(ICMPProbeIPv4Test, testThreadPool)
{
    // // 4 threads
    // asio2::iopool iopool(4);
    // //
    // // iopool must start first, othwise the server.start will blocked forever.
    // iopool.start();
    //
    // std::vector<std::future<void>> futures;
    //
    // iopool.post([]()
    // {
    //     std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    //     std::cout << "task 1:" << std::this_thread::get_id() << std::endl;
    // });
    //
    // iopool.post([]()
    // {
    //     std::this_thread::sleep_for(std::chrono::milliseconds(100));
    //     std::cout << "task 2:" << std::this_thread::get_id() << std::endl;
    // });
    //
    // iopool.post(2, [&iopool]()
    // {
    //     std::cout << "task 3:" << std::this_thread::get_id() << std::endl;
    //     ASIO2_ASSERT(iopool.get_thread_id(2) == std::this_thread::get_id());
    //     ASIO2_ASSERT(iopool.get(2)->get_thread_id() == std::this_thread::get_id());
    //     asio2::ignore_unused(iopool);
    // });

    // futures.emplace_back(std::move(future1));
    // futures.emplace_back(std::move(future2));
    // futures.emplace_back(std::move(future3));
    //
    // for (auto& future : futures)
    // {
    //     future.wait();
    // }

    //// --------------------------------------------------------------------------------

    // asio2::timer timer(iopool.get(std::rand() % iopool.size()));
    //
    // timer.start_timer(1, std::chrono::milliseconds(1000), [&]()
    // {
    //     printf("timer 1, loop infinite\n");
    // });

    //-----------------------------------------------------------------------------------

    //-----------------------------------------------------------------------------------

    // if you create a object and it will destroyed before iopool.stop(), you must create
    // the object as shared_ptr<asio2::tcp_client>, can't be asio2::tcp_client.
    {
        // 4 threads
        // asio2::iopool iopool(4);
        //
        // iopool must start first, othwise the server.start will blocked forever.
        // iopool.start();

        // std::jthread([] {
        //     std::mutex mtx;
        //     std::condition_variable cv;
        //
        //     std::shared_ptr<asio2::ping_ipv4> pingPtr = std::make_shared<asio2::ping_ipv4>();
        //
        //     pingPtr->set_timeout(1s);
        //
        //     pingPtr->bind_init([pingPtr] {
        //         // 绑定请求从哪个网口发送
        //         asio::ip::icmp::endpoint endpoint{asio::ip::address_v4::from_string("192.168.0.110"), 0};
        //         pingPtr->socket().bind(endpoint);
        //     });
        //
        //     pingPtr->bind_recv([pingPtr, &mtx, &cv](asio2::icmpv4_rep& rep){
        //         std::cout << "bind_recv: " << std::endl;
        //         std::cout << "获取到了 " << rep.get_milliseconds() << std::endl;
        //         std::unique_lock<std::mutex> lock(mtx);
        //         cv.notify_one();
        //     });
        //
        //     pingPtr->bind_stop([pingPtr] {
        //         std::cout << "bind_stop: " << std::endl;
        //     });
        //
        //     pingPtr->start("6.6.6.6");
        //
        //     std::unique_lock<std::mutex> lock(mtx);
        //     cv.wait(lock);
        //
        //     pingPtr->stop();
        //     pingPtr->destroy();
        //
        //     std::cout << "执行了stop方法" << std::endl;
        //
        // }).detach();

        // client->async_send("i love you");

        while (std::getchar() != '\n');
    }

    //-----------------------------------------------------------------------------------


    // std::vector<std::shared_ptr<asio2::ping_ipv4>> clients;
    //
    // for (int i = 0; i < 10; i++)
    // {
    //     std::shared_ptr<asio2::ping_ipv4>& client_ptr = clients.emplace_back(
    //         std::make_shared<asio2::ping_ipv4>(iopool.get(i % iopool.size())));
    //
    //     client_ptr->bind_recv([client_ptr](asio2::icmpv4_rep& rep){
    //         std::cout << "获取到了 " << rep.get_milliseconds() << std::endl;
    //     });
    //
    //     client_ptr->start("127.0.0.1");
    // }

    while (std::getchar() != '\n');  // press enter to exit this program

    /* call the server.stop and client.stop, or not call the server.stop and client.stop, is OK.*/

    //server.stop();

    //for (auto& client_ptr : clients)
    //{
    //	client_ptr->stop();
    //}

    // must call iopool.stop() before exit.
    // iopool.stop();

}

TEST(ICMPProbeTest, testExecuteIPv4)
{
    // asio2::icmpv4_rep rep = asio2::ping_ipv4::execute("192.168.0.108", "baidu.com", 8s, "Hello");
    //
    // // std::cout << rep.base_icmp().code()
    // std::cout << rep.milliseconds() << std::endl;
}

// identifier的随机数生成器
static std::mt19937 s_identifierGen{std::random_device{}()};
static std::uniform_int_distribution<std::uint16_t> s_identifierDistribute{};

TEST(ICMPProbeTest, testExecuteIPv6)
{
    // auto a = std::mt19937{std::random_device{}()};
    // auto s_identifierDistribute = std::uniform_int_distribution<std::uint16_t>{};

    auto r = s_identifierDistribute(s_identifierGen);

    std::cout << r << std::endl;

    // asio2::ping_ipv6 ping;
    //
    // // ipv6中不能自己ping自己
    // asio2::icmpv6_rep rep = ping.execute("fd00:7860:5bfc:44d0:542d:b54d:f171:b188", "fd00:7860:5bfc:44d0:869:8197:eaf0:fd51", 8s, "Hello");
    //
    // // std::cout << rep.base_icmp().code()
    // std::cout << rep.milliseconds() << std::endl;
}

TEST(ICMPProbeTest, testExecuteDNS)
{
    boost::asio::io_context io_context;

    boost::asio::ip::tcp::resolver resolver(io_context);

    resolver.async_resolve("www.baidu.com", "80");

    // auto a = std::mt19937{std::random_device{}()};
    // auto s_identifierDistribute = std::uniform_int_distribution<std::uint16_t>{};

    auto r = s_identifierDistribute(s_identifierGen);

    std::cout << r << std::endl;

    // asio2::ping_ipv6 ping;
    //
    // // ipv6中不能自己ping自己
    // asio2::icmpv6_rep rep = ping.execute("fd00:7860:5bfc:44d0:542d:b54d:f171:b188", "fd00:7860:5bfc:44d0:869:8197:eaf0:fd51", 8s, "Hello");
    //
    // // std::cout << rep.base_icmp().code()
    // std::cout << rep.milliseconds() << std::endl;
}

TEST(ICMPProbeTest, testThreadpool)
{
    boost::asio::thread_pool pool{4};

    boost::asio::post(pool, [&] {
        std::cout << "task1 :" << std::this_thread::get_id() << std::endl;
        std::this_thread::sleep_for(1s);
    });

    boost::asio::post(pool, [&] {
        std::cout << "task2 :" << std::this_thread::get_id() << std::endl;
        std::this_thread::sleep_for(2s);
    });

    pool.join();

    std::cout << "主线程任务：" << std::this_thread::get_id() << std::endl;


}

TEST(ICMPProbeTest, testistream)
{
    boost::asio::streambuf streambuf;

    std::istream{std::addressof(streambuf)};

    std::stringbuf sbuf;
    sbuf.str("HELLO1234567890");

    boost::asio::const_buffer constBuffer = boost::asio::buffer("");

    char c1[5];
    char c2[100];

    std::istream is{std::addressof(sbuf)};
    is >> c1 >> c2;

    if (is) {
        std::cout << "Hello" << std::endl;
    }
}

TEST(ICMPProbeTest, testTime)
{
    // 获取系统当前时间
    time_t nowtime = time(nullptr);
    // time_t本质是个整型
    std::cout << nowtime << std::endl;

    // 把time_t转为字符串
    const char* ct = ctime(&nowtime);
    std::cout << ct << std::endl;
}

// class Session : public std::enable_shared_from_this<Session>
// {
// public:
//     Session(boost::asio::ip::tcp::socket socket) : m_socket(std::move(socket)) {}
//
//     void start()
//     {
//         _doRead();
//     }
//
// private:
//     void _doRead()
//     {
//         auto self{shared_from_this()};
//         m_socket.async_read_some(boost::asio::buffer(m_readBuffer, MAX_PACKET_LENGTH), [this, self](boost::system::error_code ec, std::size_t bytesTransferred) {
//             if (ec) {
//                 _doClose();
//                 return;
//             }
//             _doRead();
//         });
//     }
//
//     void _doWrite()
//     {
//         auto self{shared_from_this()};
//         m_socket.async_write_some(boost::asio::buffer(m_readBuffer, MAX_PACKET_LENGTH), [this, self](boost::system::error_code ec, std::size_t bytesTransferred) {
//             if (ec) {
//                 _doClose();
//                 return;
//             }
//             _doRead();
//         });
//     }
//
//     void _doClose()
//     {
//         boost::system::error_code ec;
//         m_socket.close(ec);
//     }
//
// private:
//     boost::asio::ip::tcp::socket m_socket;
//     enum {MAX_PACKET_LENGTH = 1024};
//     char m_readBuffer[MAX_PACKET_LENGTH];
// };
//
// class Server
// {
// public:
//     Server(asio::io_context& io_context, unsigned short port) : m_acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
//     {
//
//     }
//
// private:
//     void doAccept()
//     {
//         // 本质上就是一个socket
//         m_acceptor.async_accept([this](boost::system::error_code errorCode, asio::ip::tcp::socket socket) {
//             // 如果没有错误，则构建了一个新的连接
//             if (!errorCode) {
//                 std::make_shared<Session>(socket)->start();
//             }
//         });
//     }
//
// private:
//     asio::ip::tcp::acceptor m_acceptor;
// };

boost::asio::awaitable<void> listen()
{
    // // 拿到当前的coroutine对象
    // auto executor = co_await boost::asio::this_coro::executor;
    // boost::asio::ip::tcp::acceptor acceptor{executor, {boost::asio::ip::tcp::v4(), 0}};
    // for (;;) {
    //     boost::asio::ip::tcp::socket socket = co_await acceptor.async_accept(boost::asio::use_awaitable);
    // }
}

TEST(ICMPProbeTest, testASIO)
{
    std::string ip{"192.168.0.102"};

    boost::system::error_code ec;

    boost::asio::ip::address ipAddress = boost::asio::ip::make_address(ip, ec);

    // 报错了
    if (ec.value() != 0) {
        std::cout << "error: " << ec.value() << " msg: " << ec.message() << std::endl;
    }

    boost::asio::ip::tcp::endpoint ep{ipAddress, 0};

    // try {
    //     // 内部管理一个队列
    //     boost::asio::io_context io_context{1};
    //
    //     // 准备信号 SIGINT(ctrl+c) SIGTERM(中断) 监听io_context的信号
    //     boost::asio::signal_set signals{io_context, SIGINT, SIGTERM};
    //     signals.async_wait([&](auto, auto) {
    //         std::cout << "接收到信号了" << std::endl;
    //         io_context.stop();
    //     });
    //
    //     boost::asio::co_spawn(io_context, listen(), boost::asio::detached);
    //
    //     io_context.run();
    // }
    // catch (std::exception& e) {
    //     std::cout << e.what() << std::endl;
    // }
}

}
